package com.example.testasm;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.AdviceAdapter;

/**
 * Created by 周楷桐 on 2021/12/26.
 * Description: 
 */
public class TimeMethodVisitor extends AdviceAdapter {

    private int startTimeIndex; //0
    private int endTimeIndex; //2

    protected TimeMethodVisitor(int api, MethodVisitor methodVisitor, int access, String name, String descriptor) {
        super(api, methodVisitor, access, name, descriptor);
    }

    @Override
    protected void onMethodEnter() {

        startTimeIndex = newLocal(Type.LONG_TYPE);
        visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
        visitVarInsn(LSTORE, startTimeIndex);

        super.onMethodEnter();
    }

    @Override
    protected void onMethodExit(int opcode) {

        endTimeIndex = newLocal(Type.LONG_TYPE);

        visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        visitTypeInsn(NEW, "java/lang/StringBuilder");
        visitInsn(DUP);
        visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
        visitLdcInsn("executed time : ");
        visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
        visitVarInsn(LLOAD, endTimeIndex);
        visitVarInsn(LLOAD, startTimeIndex);
        visitInsn(LSUB);
        visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(J)Ljava/lang/StringBuilder;", false);
        visitLdcInsn(" :ms");
        visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
        visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
        visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

        super.onMethodExit(opcode);
    }
}
